package com.javasm.security;

import com.javasm.commons.entity.CrmProperties;
import com.javasm.commons.util.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;//未登录访问授权资源，认证失败处理
    @Resource
    private CrmProperties crmProperties;
    /**
     * 声明一个 PasswordEncoder ，这样数据库存储的密码就不需要 "{加密方式}"，这样的前缀
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String abc123 = bCryptPasswordEncoder.encode("abc123");
        System.out.println(abc123);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 匿名登录:登录后就不可以访问,如果前端在登录后需要再次访问登录接口，使用这个不合适
         * permitAll:放行,走过滤器链。所以这里的请求不能被过滤器链拦截 (/login)
         * get 请求
         *
         */
        //方法1：使用自定义的CorsFilter过滤器，依赖下面配置类的CorsFilter对象
        //http.addFilterBefore(corsFilter, LogoutFilter.class);
        //方法2：启用Security过滤器链中的CorsFilter，依赖下面配置的UrlBasedCorsConfigurationSource对象
        http.cors().configurationSource(corsConfiguration());
        http.authorizeRequests()
                .antMatchers("/verifyCode","/doLogin","/oss/download").permitAll()// 获取验证码操作，允许匿名登录
                .anyRequest().authenticated();

        http.addFilterBefore(jwtTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        //这里设置最终认证失败处理，当未登录，直接访问需要认证后才可以访问的资源时，由这里处理
        http.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint);
        //此时session没有用，可以禁用
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();
    }

    //token拦截过滤器
    public JwtTokenAuthenticationFilter jwtTokenAuthenticationFilter(){
        return new JwtTokenAuthenticationFilter();
    }

    public UrlBasedCorsConfigurationSource corsConfiguration()
    {
        CrmProperties.Cors cors = crmProperties.getCors();

        Map<String, CorsConfiguration> configurationMap = new HashMap<>();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(cors.getAllowedOrigins());

        if (cors.getAllowedMethods().size() == 0)
            config.addAllowedMethod("*");
        else
            config.setAllowedMethods(cors.getAllowedMethods());

        if (cors.getAllowedHeaders().size() == 0)
            config.addAllowedHeader("*");
        else
            config.setAllowedHeaders(cors.getAllowedHeaders());

        if (cors.getExposedHeaders() != null && cors.getExposedHeaders().size() > 0)
            config.setExposedHeaders(cors.getExposedHeaders());

        if (cors.getMaxAge() != null)
            config.setMaxAge(cors.getMaxAge());

        if (cors.getAllowCredentials() != null)
            config.setAllowCredentials(cors.getAllowCredentials());

        configurationMap.put(cors.getPath(), config);

        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
        configurationSource.setCorsConfigurations(configurationMap);
        return configurationSource;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
